#include "Config.h"
#include "CSVReader.h"
#include "wch/StringTokenizer.h"
using namespace wch;

CSVReader::CSVReader( const std::string& file_, char ft_, char lt_, char ec_ )
	: _ft( ft_ ), _lt( lt_ ), _ec( ec_ ), _pos( 0 ), _file( file_ )
{

}

CSVReader::~CSVReader()
{
	//over();
}

bool CSVReader::split( const std::string& line, std::vector<std::string>& fields )
{
	StringTokenizer tokenizer( line, ",", StringTokenizer::TOK_TRIM );
	for ( size_t i = 0; i < tokenizer.count(); ++ i )
		fields.push_back( tokenizer[i] );
	return true;
}

static bool find_field( const std::string& str1, const std::string& str2 )
{
	return strcasecmp( str1.c_str(), str2.c_str() ) == 0;
}

bool CSVReader::prepare( const std::string& fields )
{
	_ifs.open( _file, std::ifstream::in );
	if ( !_ifs ) return false;
	//read all fields
	if ( !_ifs.eof() )
	{
		std::string line;
		std::getline( _ifs, line, _lt );
		split( line, _allFields );
	}
	else
	{
		_ifs.close();
		return false;
	}
	using namespace std::placeholders;
	_fpositions.resize( _allFields.size() );
	for ( size_t i = 0; i < _allFields.size(); ++ i )
	{
		auto fpos = std::find_if( _allFields.begin(), _allFields.end(), std::bind( find_field, _1, _allFields[i] ) );
		if ( fpos == _allFields.end() )
		{
			_ifs.close();
			return false;
		}
		_fpositions[i] = fpos - _allFields.begin();
	}
	return true;
}

void CSVReader::over()
{
	_ifs.close();
}

bool CSVReader::next()
{
	if ( _ifs.eof() )
		return false;
	std::string line;
	std::getline( _ifs, line, _lt );
	if ( line.empty() )
		return false;
	_values.clear();
	_values.resize( _allFields.size() );
	_pos = 0;	//for next read
	size_t pos = 0;
	size_t index = 0;
	while ( pos < line.length() )
	{
		if ( line[pos] == _ec )
		{
			size_t found = line.find_first_of( _ec, pos + 1 );
			if ( found == std::string::npos )
				return false;
			_values[index ++] = line.substr( pos + 1, found - pos - 1 );
			pos = found + 1;
		}
		else
		{
			size_t found = line.find_first_of( _ft, pos );
			if ( found == std::string::npos )
			{
				_values[index ++] = line.substr( pos, found );
				break;
			}
			else
				_values[index ++] = line.substr( pos , found - pos );
			pos = found;
		}
		++ pos;
	}
	return true;
}

std::string& CSVReader::operator[]( size_t pos )
{
	static std::string null = "";
	ASSERT( pos < _fpositions.size() );
	//if ( pos >= _fpositions.size() )
	//	return null;
	return _values[_fpositions[pos]];
}

std::string& CSVReader::read()
{
	static std::string null = "";
	ASSERT( _pos < _fpositions.size() );
	//if ( _pos >= _fpositions.size() )
	//	return null;
	return _values[_fpositions[_pos++]];
}